Skip to content

fix: preserve unqualified references in methods - #10679

Open
dmadisetti wants to merge 2 commits into
mainfrom
dm/mo-7484-lexical-scope
Open

fix: preserve unqualified references in methods#10679
dmadisetti wants to merge 2 commits into
mainfrom
dm/mo-7484-lexical-scope

Conversation

@dmadisetti

@dmadisetti dmadisetti commented Aug 27, 2026

Copy link
Copy Markdown
Member

Summary

Followup for the comments on #10678.

We previously only had a scope distinction for comprehensions (is_comprehension), the review bots in #10678, rightly caught that because class scoping works differently from function scoping, the recursive reference calls did not work in classes.

This PR:

  • generalizes the lexical scope types
  • adds in the condition to account for the recursive call defined in classes
  • distinguished "method" from function for variable type.

@vercel

vercel Bot commented Aug 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
marimo-docs Ready Ready Preview Sep 1, 2026 5:40pm UTC

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

You’re at about 99% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Re-trigger cubic

@dmadisetti dmadisetti added the bug Something isn't working label Aug 27, 2026
Base automatically changed from dm/mo-7484 to main September 1, 2026 17:38
@dmadisetti
dmadisetti force-pushed the dm/mo-7484-lexical-scope branch from df71755 to 68a78f3 Compare September 1, 2026 17:38
@dmadisetti
dmadisetti marked this pull request as ready for review September 1, 2026 20:31
Copilot AI lite review requested due to automatic review settings September 1, 2026 20:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refines ScopedVisitor’s name-resolution model by generalizing scope tracking (beyond comprehensions) and treating class-defined functions as “methods” so unqualified references inside method bodies are preserved as external refs (matching Python’s runtime lookup rules).

Changes:

  • Introduces a LexicalScope enum and replaces the prior is_comprehension flag with a generalized scope_kind.
  • Distinguishes VariableData.kind="method" vs "function" for FunctionDef/AsyncFunctionDef based on whether the enclosing scope is a class.
  • Adds a regression test covering the difference between method bodies (don’t resolve through class scope) and nested functions (do resolve through enclosing function scope).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
marimo/_ast/visitor.py Generalizes scope tracking and adjusts reference/definition handling to preserve unqualified refs in methods.
tests/_ast/test_visitor.py Adds a regression test for method-vs-function name resolution behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +2046 to +2070
def test_function_name_resolution_in_class_and_function_scopes() -> None:
code = cleandoc(
"""
class C:
def method(self):
return method()

def outer():
def method():
return method()
return method
"""
)
v = visitor.ScopedVisitor()
mod = ast.parse(code)
v.visit(mod)

# A bare name in a method body does not resolve through the class scope.
assert v.refs == {"method"}
assert v.variable_data["C"][0].required_refs == {"method"}

# A nested function does resolve its name through its enclosing function.
assert v.variable_data["outer"][0].required_refs == set()


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants